#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "PackageableElement.h"
#include "TypedElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class ParameterableElement;

/// <summary>
/// ValueSpecification
/// A ValueSpecification is the specification of a (possibly empty) set of values. A
/// ValueSpecification is a ParameterableElement that may be exposed as a formal
/// TemplateParameter and provided as the actual parameter in the binding of a
/// template.
/// </summary>
class UMLMODEL_EXPORT ValueSpecification : public TypedElement, public PackageableElement {

public: // Constructors and destructors
    explicit ValueSpecification(const QString& umlType="uml::ValueSpecification");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// booleanValue
    /// The query booleanValue() gives a single Boolean value when one can be computed.
    /// </summary>
    virtual bool booleanValue() const;

    /// <summary>
    /// integerValue
    /// The query integerValue() gives a single Integer value when one can be computed.
    /// </summary>
    virtual int integerValue() const;

    /// <summary>
    /// isCompatibleWith
    /// The query isCompatibleWith() determines if this ValueSpecification is compatible
    /// with the specified ParameterableElement. This ValueSpecification is compatible
    /// with ParameterableElement p if the kind of this ValueSpecification is the same
    /// as or a subtype of the kind of p. Further, if p is a TypedElement, then the type
    /// of this ValueSpecification must be conformant with the type of p.
    /// </summary>
    bool isCompatibleWith(shared_ptr<ParameterableElement> p) const override;

    /// <summary>
    /// isComputable
    /// The query isComputable() determines whether a value specification can be
    /// computed in a model. This operation cannot be fully defined in OCL. A conforming
    /// implementation is expected to deliver true for this operation for all
    /// ValueSpecifications that it can compute, and to compute all of those for which
    /// the operation is true. A conforming implementation is expected to be able to
    /// compute at least the value of all LiteralSpecifications.
    /// </summary>
    virtual bool isComputable() const;

    /// <summary>
    /// isNull
    /// The query isNull() returns true when it can be computed that the value is null.
    /// </summary>
    virtual bool isNull() const;

    /// <summary>
    /// realValue
    /// The query realValue() gives a single Real value when one can be computed.
    /// </summary>
    virtual double realValue() const;

    /// <summary>
    /// stringValue
    /// The query stringValue() gives a single String value when one can be computed.
    /// </summary>
    virtual QString stringValue() const;

    /// <summary>
    /// unlimitedValue
    /// The query unlimitedValue() gives a single UnlimitedNatural value when one can be
    /// computed.
    /// </summary>
    virtual int unlimitedValue() const;

};

} // namespace uml
